
   //
   // Load a xml file remotely
   //
   function loadAndProcessXmlFile( xmlFile, bikeMgr ) {
      bikeMgr.log("loadAndProcessXmlFile( " + xmlFile + " ) ");
	 
      var request = google.maps.XmlHttp.create();
      request.open("GET", xmlFile, true );
      request.onreadystatechange = function() {

      // Read Contents and set the Points/Markers
      if (request.readyState == 4) {
    
          // Create Tail object assign to element in associative fashion
          var trail = new Trail();
          trail.name = xmlFile;
          var fileIndex = bikeMgr.listOfTrails.length;
          bikeMgr.listOfTrails[ fileIndex ] = trail;
    
          // Get the XML document
          var xmlDoc = google.maps.Xml.parse(request.responseText);
          bikeMgr.processXmlDocument( xmlDoc, trail );
    
      }  // end of readyState

     } // end of function onreadystatechange()
     request.send(null);

     bikeMgr.log("finished loadAndProcessXmlFile()");
   } // end of loadAndProcessXmlFile()



   //     
   // function will show or hide a particular trail; based on the users selection
   //
   function showHideAllTrails( isChecked ) {
       bikeMgr.log("showHideAllTrails( " + isChecked + " )");

       bikeMgr.showHideAllTrails( isChecked );

   } // end of showHideAllTrails()


   //     
   // function will show or hide a particular trail; based on the users selection
   //
   function showHideTrail( trailIndex, isChecked ) {
       bikeMgr.log("showHideTrail( " + trailIndex + ", " + isChecked + " )");

       bikeMgr.log("isChecked = " + isChecked + " trail = " + bikeMgr.listOfTrails[ trailIndex ] );

       if( isChecked ) {
           bikeMgr.listOfTrails[ trailIndex ].showTrail();
       }
       else {
           bikeMgr.listOfTrails[ trailIndex ].hideTrail();
       }

   } // end of showHideTrail()


//////////////////////////////////////////////////////////
//  Trail JavaScript class defined below                //
//////////////////////////////////////////////////////////

    /**
     * Object represents a Trail in the Biking application
     * Define a JavaScript object that will contain our Trails
     */
    function Trail() {
        this.name = "";                     // Name of Trail
		this.gpolylines   = new Array();    // Polylines on map
        this.gmarkers     = new Array();    // Line Markers on map
        this.tlabels      = new Array();    // TLabels on map
        this.cyclemarkers = new Array();    // Cycle Markers on map
        this.zoomLevel    = new Number(13); // Zoom Level when Trail appears

        /**
	     * function will hide this trails contents
         */
	    this.hideTrail = function() {

            // Hide Polylines
            for( var index=0; index < this.gpolylines.length; index++ ) {
                if( this.gpolylines[index].supportsHide() ) {
                   this.gpolylines[index].hide();
                }
                else {
                   map.removeOverlay( this.gpolylines[index] );
                }
            }

            // Hide Markers
            for( var index=0; index < this.gmarkers.length; index++ ) {
               this.gmarkers[index].hide();
            }

            // Hide Cycle Markers
            for( var index=0; index < this.cyclemarkers.length; index++ ) {
               this.cyclemarkers[index].hide();
            }

            // Hide Labels
            for( var index=0; index < this.tlabels.length; index++ ) {
               this.tlabels[index].hide();
            }
        } // end of hideTrail()

        /**
         * Function will show this trail
         */
	    this.showTrail = function() {
			  
          // Show Polylines
          for( var index=0; index < this.gpolylines.length; index++ ) {
              this.gpolylines[index].show();
          }

          // Show Markers
          for( var index=0; index < this.gmarkers.length; index++ ) {
             this.gmarkers[index].show();
          }

          // Show Cycle Markers
          for( var index=0; index < this.cyclemarkers.length; index++ ) {
             this.cyclemarkers[index].show();
          }

          // Show Labels
          for( var index=0; index < this.tlabels.length; index++ ) {
             this.tlabels[index].show();
          }
			  
        } // end of showTrail()


        /**
         * Function will show the Cycle Markers
         */
	    this.showCycleMarkers = function() {
			  
          // Show Cycle Markers
          for( var index=0; index < this.cyclemarkers.length; index++ ) {
             this.cyclemarkers[index].show();
          }
			  
        } // end of showCycleMarkers()

    }  // end of Trail Object
			   

//////////////////////////////////////////////////////////
//  BikeTrailManager JavaScript class defined below        //
//////////////////////////////////////////////////////////

   /**
    * Constructor for BikeTrailManager
    */
   function BikeTrailManager() {
      this.map = new Object();            // Google GMap2 object
      this.isLoggingOn  = false;          // If Google Debugger is on
      this.listOfTrails = new Array();    // List of Trail objects
      this.mapTooltip   = new Object();   // Tooltip for Markers
   }


   // Create a line
   BikeTrailManager.prototype.createLines = function( lines, theTrail ) {
       this.log("BikeTrailManager.createLines()");

       for( var a = 0; a < lines.length; a++ ) {
           var polyLine = this.createLine( lines[a] );
           theTrail.gpolylines[ a ] = polyLine;
		   
           var color = lines[a].getElementsByTagName("colour");
           this.createLineMarkers( lines[a], theTrail, color );
       } // end of for-loop lines

   } // end of createLines()

   /**
    *
    */
   BikeTrailManager.prototype.createMarkers = function( markers, theTrail ) {
       this.log("BikeTrailManager.createMarkers()");

       for (var i = 0; i < markers.length; i++) {

           // obtain the attribues of each marker
           var lat = parseFloat(markers[i].getAttribute("lat"));
           var lng = parseFloat(markers[i].getAttribute("lng"));
           var point = new google.maps.LatLng(lat,lng);

           var html  = markers[i].getAttribute("html");
           var label = markers[i].getAttribute("label");
           var image = markers[i].getAttribute("image");

           // create the marker
           var isCycle = markers[i].getAttribute("markertype");
           var marker;
           if( isCycle == "cycle" ) {
               marker = this.createCycleMarker(point,label,html);

		       // Add Cycle Marker to Trail object
   		       var index = theTrail.cyclemarkers.length;
               theTrail.cyclemarkers[ index ] = marker;
           }
           else {
               var color = "#00ff00";
               marker = this.createMarker(point, label, html, image, color );

		       // Add Marker to Trail object		   
               var index = theTrail.gmarkers.length;
               theTrail.gmarkers[ index ] = marker;
           }
           this.map.addOverlay(marker);

       } // end of for-loop

    } // end of createMarkers()


    /**
     * A function to create all of the Signs for a Trail
     */
    BikeTrailManager.prototype.createTrailSigns = function( trailSigns, theTrail ) {
        this.log("BikeTrailManager.createTrailSigns()");

        for (var i = 0; i < trailSigns.length; i++) {

           // obtain the attribues of each marker
           var lat   = parseFloat(trailSigns[i].getAttribute("lat"));
           var lng   = parseFloat(trailSigns[i].getAttribute("lng"));
           var point = new google.maps.LatLng(lat,lng);

           var html   = trailSigns[i].getAttribute("html");
           var label  = trailSigns[i].getAttribute("label");
           var opaque = trailSigns[i].getAttribute("opaque");
           var xoff   = parseInt(trailSigns[i].getAttribute("xoffset"));
           var yoff   = parseInt(trailSigns[i].getAttribute("yoffset"));

           // create the Sign
           var offset  = new google.maps.Size(xoff, yoff);
           var sign    = this.createLabel( point, label, "style1", offset, opaque );
           this.map.addOverlay( sign );

           theTrail.tlabels[ i ] = sign;

        } // end of for-loop signs
    } // end of createTrailSigns()

   /**
    * A function to create the marker and set up the event window
    */
   BikeTrailManager.prototype.createLineMarkers = function( lineMarkers, theTrail, color ) {
       this.log("BikeTrailManager.createLineMarkers()");

       var markerPoints  = lineMarkers.getElementsByTagName("point");
       for( var a = 0; a < markerPoints.length; a++ ) {

            var image = markerPoints[a].getAttribute("image");
            if( image != null ) {
                var lat    = parseFloat(markerPoints[a].getAttribute("lat"));
                var lng    = parseFloat(markerPoints[a].getAttribute("lng"));
                var point  = new google.maps.LatLng(lat,lng);
                var elevation  = markerPoints[a].getAttribute("elevation");
                var html   = markerPoints[a].getAttribute("html");
                var label  = markerPoints[a].getAttribute("label") + " : " + elevation;
                var marker = this.createMarker( point, label, html, image, color );
                this.map.addOverlay( marker );

                var index = theTrail.gmarkers.length;
                theTrail.gmarkers[ index ] = marker;
            }

      } // end of for-loop markerPoints

   } // end of createLineMarkers()

   /**
    * A function to create the marker and set up the event window
    */
   BikeTrailManager.prototype.createLine = function( line ) {
       this.log("BikeTrailManager.createLine()");

       var colour  = line.getAttribute("colour");
       var width   = parseFloat(line.getAttribute("width"));
       var points  = line.getElementsByTagName("point");

       // Create GLatLng and GPoint
       var latLong = new Array();
       for (var i = 0; i < points.length; i++) {
           latLong[i]  = new google.maps.LatLng(parseFloat(points[i].getAttribute("lat")), parseFloat(points[i].getAttribute("lng")));
       } // end of for-loop points

       var poly = new google.maps.Polyline( latLong, colour, width);
       this.map.addOverlay( poly );

       return poly;
   } // end of createLine()

   /**
    * A function to create the marker and set up the event window
    */
   BikeTrailManager.prototype.createMarker = function(point, toolTipName, html, image, color ) {
       this.log("BikeTrailManager.createMarker()");

       var icon    = new MapIconMaker.createMarkerIcon( {width:15, height:15, primaryColor: "#00ff00"} );
       var htmlWithImage = '<div style="width:100; height:200; padding:5px">' + html + ' <img src="' + image + '" /> ' + '</div>';

       //var marker = new GMarker(point);
       var marker = new google.maps.Marker(point, icon);

       marker.tooltip = '<div class="tooltip"><nobr>' + toolTipName + '</nobr></div>';

       google.maps.Event.addListener(marker, 'click', function() {
           marker.openInfoWindowHtml( htmlWithImage );
       });
       google.maps.Event.addListener(marker, 'mouseover', function() {
           bikeMgr.showMarkerToolTip(marker);
       });
       google.maps.Event.addListener(marker, 'mouseout', function() {
           bikeMgr.mapTooltip.style.visibility="hidden";
       });

       return marker;
   } // end of createMarker()


   /**
    * This function displays the tooltip for the Marker
    */ 
   BikeTrailManager.prototype.showMarkerToolTip = function( marker ) {
      this.log("BikeTrailManager.showMarkerToolTip()");

      this.mapTooltip.innerHTML = marker.tooltip;
	  var point  =  this.map.getCurrentMapType().getProjection().fromLatLngToPixel( this.map.fromDivPixelToLatLng(new google.maps.Point(0,0),true), this.map.getZoom());
	  var offset =  this.map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(), this.map.getZoom());
	  var anchor =  marker.getIcon().iconAnchor;
	  var width  =  marker.getIcon().iconSize.width;
	  var height =  this.mapTooltip.clientHeight;
	  var pos    = new google.maps.ControlPosition(G_ANCHOR_TOP_LEFT, new google.maps.Size(offset.x - point.x - anchor.x + width, offset.y - point.y -anchor.y -height)); 
	  pos.apply( this.mapTooltip);
	  this.mapTooltip.style.visibility="visible";

   } // end of showMarkerToolTip()

   /**
    * A function to create the Cycle marker and set up the event window
    */
   BikeTrailManager.prototype.createCycleMarker = function(point,name,html) {
      this.log("BikeTrailManager.createCycleMarker()");

      var cycle   = "images/cycling.png";
      var overlay = "images/cycling.shadow.png";
      var mylabel = {"url":overlay, "anchor":new google.maps.LatLng(4,4), "size":new google.maps.Size(8,8)};
      var icon    = new google.maps.Icon(G_DEFAULT_ICON, cycle,  mylabel );
      var marker  = new google.maps.Marker(point, icon);

      // Imbed a YouTube Video
      marker.bindInfoWindow('<div style="width:450; height: 400;"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/tpjXiWaJjlg&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/tpjXiWaJjlg&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object></object></div>');

      return marker;
   } // end of createCycleMarker()

   //
   // A function to create labels on the map
   //
   BikeTrailManager.prototype.createLabel = function(point, html, style, offset, opaque ) {
       this.log("BikeTrailManager.createLabel()");

       var label = new ELabel( point, html, style, offset, opaque );

       return label;
   }


   //     
   // function will show or hide a particular trail; based on the users selection
   //
   BikeTrailManager.prototype.showHideAllTrails = function( isChecked ) {
         this.log("BikeTrailManager.showHideAllTrails( " + isChecked + " )");

         for( var index=0; index < this.listOfTrails.length; index++ ) {
            this.showHideTrail( this.listOfTrails[ index ], isChecked );
         }
   } // end of showHideAllTrails()

   //     
   // function will show or hide a particular trail; based on the users selection
   //
   BikeTrailManager.prototype.showHideTrail = function( trail, isChecked ) {
      this.log("BikeTrailManager.showHideTrail()");

      this.log("BikeTrailManager.isChecked = " + isChecked + " trail = " + trail );
      var mapZoomLevel = new Number( this.map.getZoom() );
      this.log("trail name : " + trail.name + "  map mapZoomLevel = " + mapZoomLevel + " trail.zoomLevel=" + trail.zoomLevel );
      if( isChecked ) {

          // Only Show the Cycle Markers if at a high zoom level
          if( mapZoomLevel >= trail.zoomLevel ) {	   
             this.log("show entire tail : " + trail.name );
             trail.showTrail();
          }
          else {
             this.log("show only CycleMarker : " + trail.name );
             trail.showCycleMarkers();
          }
      }
      else {
          trail.hideTrail();
      }

   } // end of showHideTrail()

   //
   // Simple logging fuction
   //
   BikeTrailManager.prototype.log = function( info ) {
      if( isLoggingOn ) {
         google.maps.Log.write( info );
      }
   }


   //
   // Adds Markers/Polylines, etc to map
   //
   BikeTrailManager.prototype.processXmlDocument = function( xmlDoc, trail ) {
      this.log("BikeTrailManager.processXmlDocument()");

      // Create Markers on Map
      var markers = xmlDoc.documentElement.getElementsByTagName("marker");
      this.createMarkers( markers, trail );
    
      // Create signs on Map
      var trailSigns = xmlDoc.documentElement.getElementsByTagName("sign");
      this.createTrailSigns( trailSigns, trail );
    
      // Create Lines on Map
      var lines = xmlDoc.documentElement.getElementsByTagName("line");
      this.createLines( lines, trail );
   }



   // Moves the map and sets the zoom
   BikeTrailManager.prototype.panToZoom = function( point, zoom ) {
       this.log("BikeTrailManager.panToZoom( point, " + zoom + " )");

       this.map.setZoom( zoom );
       this.map.panTo( point );

   } // end of panToZoom()





